package p2pgame;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import p2pgame.message.Move;
import p2pgame.message.NextTurn;

// represents a player in a Ludo game.
// A LudoApp can play in many games at the same time.
public class Player {

	public Response response = new Response(); // game states received. When 5 responses are received we want to update to the majority

	public Game game;
	LudoApp app;
	
	public Player(LudoApp app, Game game){
		this.app=app;
		this.game=game;
		
	}
	
	
	//players receive nextTurn whenever there are updates from the op's
	public void nextTurn(NextTurn message){
		int oldTurn=game.turn;
		response.receiveResponse(message.getGame());
		game.engine = response.currentGameState();
		game.turn = response.currentTurnNumber();
		if ( game.turn>oldTurn) {
			updateView();
		}
		//TODO: if ID is in turn prompt user for move
	}
	
	// all the response received from the OP's (all the NextTurn messages).
	// The peer's received ludoGame state and turn number is a function of the responses.
	public class Response{
		private int consistentTurns = -1;
		private List<TurnResponse> trList = new ArrayList<TurnResponse>();
		private TurnResponse getTurnResponse(Game game){
			for (TurnResponse tr: trList){
				if (game.turn==tr.turnNumber) return tr;
			}
			TurnResponse newTurnResponse = new TurnResponse(game.turn);
			trList.add(newTurnResponse);
			return newTurnResponse;
		}

		//must be called each time the peer receives a NextTurn message
		public void receiveResponse(Game game){
			TurnResponse tr = getTurnResponse(game);
			tr.receiveResponse(game);

			// if >3 consistent messages increase turn number
			EQ max = getTurnResponse(game).max();
			if (max!=null && max.occurrences>=3 &&
					(game.turn>this.consistentTurns) ) this.consistentTurns = game.turn;
		}
		public ludo.Engine currentGameState(){
			Collections.sort(trList);
			if ( trList.size()==0) return null;
			if ( consistentTurns < 0) return null;
			TurnResponse tr = trList.get(consistentTurns);
			EQ max = tr.max();
			if ( max==null) return null;
			return max.game.engine;
		}
		public int currentTurnNumber(){
			return consistentTurns;
		}

//		EQ resembles an equivalence class of games
		private class EQ implements Comparable<EQ>{
			public int occurrences;
			public Game game;
			public EQ(Game game, int occurrences){
				this.game = game;
				this.occurrences = occurrences;
			}
			public int compareTo(EQ other){
				if (this.occurrences > other.occurrences) return 1;
				else if (this.occurrences == other.occurrences) return 0;
				else return -1;
			}
		}

		//		the responses for a single turn
		private class TurnResponse implements Comparable<TurnResponse>{ 
			public int turnNumber;
			private List<EQ> list = new ArrayList<EQ>();
			private int number = 0;
			public TurnResponse(int turnNumber){
				this.turnNumber = turnNumber;			
			}
			private EQ getEQ(Game game){
				for (EQ eq: list){
					if (eq.game.equals(game)) return eq;
				}
				return null;
			}
			public void receiveResponse(Game game){
				if (getEQ(game)!=null) {
					getEQ(game).occurrences++;
				} else {
					EQ eq = new EQ(game, 1);
					list.add(eq);
				}
				number++;
				//TODO: report error if number>=opsPerGame
			}
			public EQ max(){
				Collections.sort(list);
				if (list.size()==0){
					return null;
				} else{
					return list.get(list.size() - 1);
				}
			}
			public int compareTo(TurnResponse other){
				if (this.turnNumber > other.turnNumber) return 1;
				else if (this.turnNumber == other.turnNumber) return 0;
				else return -1;
			}
		}

	}

	public boolean move(int square){
		//if (game.engine.move(square)){
			app.send(game.ops, new Move(app.getPeerId(),game.gameId,square));
			return true;
//		} else {
//			return false;
//		}
	}

	public void updateView() {
		int player=0;
		for(ludo.Player p: game.engine.players){
			System.out.println("\n---- PLAYER "+player+" ----");
			for(int i=0;i<p.boardSize;i++){
				if(p.board[i]>0){
					System.out.println("Square "+game.engine.index(i, player)+": "+p.board[i]+" piece(s)");
				}
			}
			player++;
		}
		System.out.println("-------------");
		System.out.println("Player turn: "+game.engine.playerInTurn);
		System.out.println("Dice: "+game.engine.dice);
	}


}
